/*
 *  AStream.h
 *  
 *
 *  Created by Peter on 23.02.12.
 *  Copyright 2012 __MyCompanyName__. All rights reserved.
 *
 */
#ifndef A_STREAM_H
#define A_STREAM_H

#include "TrCompat.h"

#include <fstream>
#include <iostream>
#include <string>

/*
 * This utility class takes care of all file I/O abstraction. We can use it to 
 * implemenent byte swapping transparently and stuff like that. We also store
 * bools and strings exactly the way the Avid does.
 *
 * This probably doesn't have much to do with Avid's actual implementation and 
 * interface of AStream, but this does the job for us and is possibly even nicer
 * than Avid's version :)
 *
 * This is never serialized itself (and hence isn't derived from AObject either)
 * so we basically have complete freedom in the design of this class.
 *
 * TODO: Replace readPod/writePod by standard C++ stream operators, it's just a 
 *       lot less typing. Should have done that from the start.
 */
class AStream
{
	
public:
	
	AStream( const std::string& fileName );
	
	~AStream();
	
	// Set if you want the stream to do automatic byte swapping for you
	void setSwapBytes( bool value );
	
	// Read a string from the file
	std::string readString();
	
	// Write a string to the file
	void writeString( const std::string& str );
	
	// Read a POD (plain old data, like an int) type from the stream
	template< typename T >
	void readPod( T& value );
		
	// Write a plain old data type (like an int) to the file
	template< typename T >
	void writePod( T value );
	
	// Seek numBytes forward from the current position
	void skip( int numBytes );
	
	// Move the reading positions numBytes from the current one
	void seekRelative( int numBytes );
		
	bool readBool();
	
	void writeBuffer( void* buffer, std::size_t size );
	
	// Read the given number of bytes from the stream into the given buffer
	void readBuffer( void* buffer, std::size_t size );
	
	UInt8 peek();
	
	// Returns the current position in the stream
	std::streampos getPos() const;
	
protected:
	
	void swapBytes( UInt16& value );
	void swapBytes( UInt32& value );
	void swapBytes( Int16& value );
	void swapBytes( Int32& value );
	void swapBytes( Int64& value );
	
	inline void swapBytes( Int8&  value ){};
	inline void swapBytes( UInt8& value ){};
	
	void swapBytes( Float64& value );
	
	// ----- data members -----
	
	bool         _swapBytes;
	std::fstream _stream;
	
};

template< typename T >
void AStream::writePod( T value )
{
	if( _swapBytes )
		swapBytes( value );
		
	// FIXME: Only do this for integers, not structs!!! There has to be some
    // kind of template std::type_traits::isPod, if not, we should write that
	_stream.write (
	   reinterpret_cast< char* >( &value ),
	   sizeof( T )
	);
}

template< typename T >
void AStream::readPod( T& value )
{
	_stream.read (
		reinterpret_cast< char* >( &value ),
		sizeof( T )
	);
	
	// FIXME: Only do this for integers, not structs!!!
	if( _swapBytes )
		swapBytes( value );
}

#endif /*Inclusion Guard*/